package com.fgxia.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fgxia.admin.service.IAdminOrderService;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.domain.bo.OrderFeeBo;
import com.ruoyi.business.domain.bo.admin.AdminOrderAddBo;
import com.ruoyi.business.domain.bo.admin.AdminOrderQueryBo;
import com.ruoyi.business.domain.bo.admin.AdminPriceEditBo;
import com.ruoyi.business.domain.bo.admin.AdminUploadBillBo;
import com.ruoyi.business.domain.vo.*;
import com.ruoyi.business.domain.vo.admin.*;
import com.ruoyi.business.mapper.*;
import com.ruoyi.business.utils.OrderUtils;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.PushTemplate;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.event.PushMessageEvent;
import com.ruoyi.common.core.domain.event.WarningEvent;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.AreaService;
import com.ruoyi.common.enums.*;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 订单 服务实现
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AdminOrderServiceImpl implements IAdminOrderService {

    private final OrderInfoMapper orderInfoMapper;
    private final FreightInfoMapper freightInfoMapper;
    private final OrderFeeMapper orderFeeMapper;
    private final OrderFeeConfigMapper feeConfigMapper;
    private final OrderRevaluationHistoryMapper revaluationHistoryMapper;
    private final OrderPaymentVoucherMapper paymentVoucherMapper;

    private final SysUserMapper userMapper;
    private final SysUserLoginCompanyMapper companyMapper;
    private final AreaService areaService;

    /**
     * 获取订单详情(编辑用)
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderInfoVo selectOrderById(Long orderId) {
        OrderInfoVo orderInfoVo = orderInfoMapper.selectVoById(orderId);
        orderInfoVo.setOrderFeeList(orderFeeMapper.selectVoListByMasterId(orderInfoVo.getOrderId()));
        return orderInfoVo;
    }

    /**
     * 获取订单详情（查询用）
     *
     * @param orderId
     * @return
     */
    @Override
    public AdminOrderQueryVo queryOrderById(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo == null) {
            throw new ServiceException("订单不存在");
        }
        // 订单信息
        AdminOrderQueryVo orderQueryVo = BeanCopyUtils.copy(orderInfo, AdminOrderQueryVo.class);
        if (orderQueryVo == null) {
            throw new ServiceException("查询订单失败");
        }
        // 公司简称
        SysUserLoginCompany company = companyMapper.selectByUserId(orderInfo.getRelevanceUserId());
        if (company != null) {
            orderQueryVo.setSendCompanyAbbreviation(company.getCompanyAbbreviation());
        }
        // 车辆信息
        List<AdminOrderDriverVo> orderDriverVos = orderInfoMapper.selectDriverVoList(orderId);
        orderQueryVo.setOrderDriverVoList(orderDriverVos);
        // 费用信息
        List<OrderFeeVo> orderFeeVos = orderFeeMapper.selectVoListByMasterId(orderId);
        orderQueryVo.setOrderFeeList(orderFeeVos);
        // 打款信息
        OrderPaymentVoucherVo orderPaymentVoucherVo = paymentVoucherMapper.selectByMasterId(orderId);
        orderQueryVo.setOrderPaymentVoucherVo(orderPaymentVoucherVo);

        return orderQueryVo;
    }

    /**
     * 新增订单
     *
     * @param orderAddBo 订单新增业务对象
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public OrderResultVo insertOrder(AdminOrderAddBo orderAddBo) {
        OrderInfo orderInfo = BeanCopyUtils.copy(orderAddBo, OrderInfo.class);
        if (orderInfo == null) {
            throw new ServiceException("新增订单失败");
        }

        // 创建时根据发货人手机号关联其对应手机号的用户
        if (StrUtil.isNotBlank(orderInfo.getSendPhone())) {
            SysUserLoginCompany company = companyMapper.selectByPhone(orderInfo.getSendPhone());
            if (company == null) {
                company = this.insertCompany(orderAddBo);
            }
            orderInfo.setRelevanceUserId(company.getRelevanceUserId());
        } else {
            orderInfo.setRelevanceUserId(LoginHelper.getUserId());
        }

        // 插入订单
        orderInfo.setOrderNo(OrderUtils.generateOrderNo(orderInfo.getRelevanceUserId()));
        orderInfo.setOrderStatus(OrderStatus.INITIALIZED.getCode());


        List<OrderFeeBo> orderFeeList = orderAddBo.getOrderFeeList();
        List<OrderFee> orderFees = BeanCopyUtils.copyList(orderFeeList, OrderFee.class);
        if (orderFees == null) {
            orderFees = new ArrayList<>();
        }
        // 算出订单总费用
        BigDecimal orderTotalAmount = orderFees.stream()
            .map(OrderFee::getAmount)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        orderInfo.setOrderTotalPrices(orderTotalAmount);
        orderInfo.setRemainingInvoiceAmount(orderTotalAmount);

        int insert = orderInfoMapper.insert(orderInfo);
        if (insert <= 0) {
            throw new ServiceException("新增订单失败");
        }

        if (!orderFees.isEmpty()) {
            for (OrderFee orderFee : orderFees) {
                orderFee.setOrderId(orderInfo.getOrderId());
            }
            orderFeeMapper.insertBatch(orderFees);
        }

        return OrderResultVo.builder()
            .orderId(orderInfo.getOrderId())
            .build();
    }

    /**
     * 修改订单
     *
     * @param orderAddBo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public OrderResultVo updateOrder(AdminOrderAddBo orderAddBo) {
        Long orderId = orderAddBo.getOrderId();
        OrderInfo oldInfo = orderInfoMapper.selectById(orderId);
        if (oldInfo == null) {
            throw new ServiceException("订单不存在");
        }
        // 配送中就不能改了
        if (!OrderStatus.INITIALIZED.getCode().equals(oldInfo.getOrderStatus())) {
            throw new ServiceException("该订单已被接单，不能修改");
        }

        OrderInfo orderInfo = BeanCopyUtils.copy(orderAddBo, OrderInfo.class);
        if (orderInfo == null) {
            throw new ServiceException("修改订单失败");
        }

        // 如果是运营添加的订单，而且没有设置设置关联用户，那么允许去查询关联用户
        if (oldInfo.getRelevanceUserId() == null ||
            (oldInfo.getRelevanceUserId().equals(LoginHelper.getUserId()) &&
                oldInfo.getIsOperationAdd().equals(SysYesNo.Y.name()))
        ) {
            // 创建时根据发货人手机号关联其对应手机号的用户
            if (StrUtil.isNotBlank(orderInfo.getSendPhone())) {
                SysUserLoginCompany company = companyMapper.selectByPhone(orderInfo.getSendPhone());
                if (company == null) {
                    company = this.insertCompany(orderAddBo);
                }
                orderInfo.setRelevanceUserId(company.getRelevanceUserId());
            } else {
                orderInfo.setRelevanceUserId(LoginHelper.getUserId());
            }

            orderInfo.setOrderNo(OrderUtils.generateOrderNo(orderInfo.getRelevanceUserId()));
        }

        orderInfo.setOrderStatus(OrderStatus.INITIALIZED.getCode());

        List<OrderFeeBo> orderFeeList = orderAddBo.getOrderFeeList();
        List<OrderFee> orderFees = BeanCopyUtils.copyList(orderFeeList, OrderFee.class);
        if (orderFees == null) {
            orderFees = new ArrayList<>();
        }

        // 算出订单总费用
        BigDecimal orderTotalAmount = orderFees.stream()
            .map(OrderFee::getAmount)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        orderInfo.setOrderTotalPrices(orderTotalAmount);
        orderInfo.setRemainingInvoiceAmount(orderTotalAmount);

        int insert = orderInfoMapper.updateById(orderInfo);
        if (insert <= 0) {
            throw new ServiceException("新增订单失败");
        }

        orderFeeMapper.deleteByMasterId(orderId);
        if (!orderFees.isEmpty()) {
            for (OrderFee orderFee : orderFees) {
                orderFee.setOrderId(orderInfo.getOrderId());
            }

            orderFeeMapper.insertBatch(orderFees);
        }

        return OrderResultVo.builder()
            .orderId(orderId)
            .build();
    }

    /**
     * 新增司机
     *
     * @param adminOrderAddBo
     * @return
     */
    private SysUserLoginCompany insertCompany(AdminOrderAddBo adminOrderAddBo) {
        String phonenumber = adminOrderAddBo.getSendPhone();
        SysUser user = userMapper.selectUserByPhonenumber(phonenumber);

        if (user == null) {
            user = new SysUser();
            user.setNickName("企业" + RandomUtil.randomString(8));
            user.setPhonenumber(phonenumber);
            user.setUserName(phonenumber);
            user.setStatus(UserStatus.OK.getCode());
            user.setCreateBy(LoginHelper.getUsername());
            user.setCreateTime(DateUtils.getNowDate());
            // user.setPassword(BCrypt.hashpw(user.getPassword()));
            user.setPassword(null);

            int insert = userMapper.insert(user);
            if (insert == 0) {
                log.info("公司用户：{} 注册失败.", phonenumber);
                throw new UserException("公司用户注册失败");
            }
        }

        SysUserLoginCompany company = new SysUserLoginCompany();
        company.setCompanyName(adminOrderAddBo.getSendCompanyName());
        company.setUserType(UserType.APP_COMPANY.getUserType());
        company.setSettlementType(adminOrderAddBo.getSettlementType());
        company.setProvince(adminOrderAddBo.getSendProvince());
        company.setCity(adminOrderAddBo.getSendCity());
        company.setDistrict(adminOrderAddBo.getSendDistrict());
        company.setAddress(adminOrderAddBo.getSendAddress());
        company.setRelevanceUserId(user.getUserId());
        company.setCompanyAbbreviation(String.valueOf(OrderUtils.generateRandomNumber(adminOrderAddBo.getSendCompanyName())));
        int insert = companyMapper.insert(company);
        if (insert == 0) {
            throw new ServiceException("司机创建失败");
        }

        return company;
    }

    /**
     * 获取订单可改价项
     *
     * @param orderId
     * @return
     */
    @Override
    public List<OrderFeeVo> getPriceItemVoList(Long orderId) {
        LambdaQueryWrapper<OrderFee> lqw = new LambdaQueryWrapper<OrderFee>()
            .eq(OrderFee::getOrderId, orderId);

        List<OrderFeeVo> orderFeeVos = orderFeeMapper.selectVoList(lqw);
        return orderFeeVos;
    }

    /**
     * 修改订单价格
     *
     * @param price
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateOrderPrice(AdminPriceEditBo price) {
        Long id = price.getMasterId();
        OrderInfo orderInfo = orderInfoMapper.selectById(id);
        if (orderInfo == null) {
            throw new ServiceException("订单不存在");
        }
        OrderFee orderFee = orderFeeMapper.selectByIdAndName(id, price.getName());
        if (orderFee == null) {
            throw new ServiceException("费用类型不存在");
        }
        OrderRevaluationHistory orderRevaluationHistory = new OrderRevaluationHistory();
        orderRevaluationHistory.setOrderId(id);
        orderRevaluationHistory.setFeeName(price.getName());
        orderRevaluationHistory.setOrderOperateUser(LoginHelper.getUserId());
        orderRevaluationHistory.setBeforeAmount(orderFee.getAmount());
        orderRevaluationHistory.setAfterAmount(price.getPrice());
        orderRevaluationHistory.setRemark(price.getRemark());
        int insert = revaluationHistoryMapper.insert(orderRevaluationHistory);
        if (insert < 0) {
            return false;
        }
        // 修改订单费用
        orderFee.setAmount(price.getPrice());
        int update = orderFeeMapper.updateById(orderFee);
        if (update == 0) {
            throw new ServiceException("修改订单费用失败");
        }

        // 重新计算订单总费用
        List<OrderFee> orderFees = orderFeeMapper.selectListByMasterId(id);
        BigDecimal orderTotalAmount = orderFees.stream()
            .map(OrderFee::getAmount)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        orderInfoMapper.update(new LambdaUpdateWrapper<OrderInfo>()
            .eq(OrderInfo::getOrderId, id)
            .set(OrderInfo::getRemainingInvoiceAmount, orderTotalAmount)
            .set(OrderInfo::getOrderTotalPrices, orderTotalAmount));

        // 插入推送
        // 推送给客户
        SpringUtils.context().publishEvent(PushMessageEvent.builder()
            .pushRef(PushRefType.ORDER_CHANGE_PRICE.getValue())
            .pushTo(PushMessageEvent.pushAll(orderInfo.getSendPhone()))
            .pushTime(new Date())
            .pushContent(PushTemplate.ORDER_CHANGE_PRICE_TEMPLATE(orderInfo.getOrderNo(), orderFee.getName(), price.getPrice(), price.getRemark()))
            .build());

        // 推送给配置表
        SpringUtils.context().publishEvent(WarningEvent.builder()
            .ownerId(orderInfo.getOrderId())
            .ownerType("order")
            .type(PushRefType.ORDER_CHANGE_PRICE.getValue())
            .content(PushTemplate.ORDER_CHANGE_PRICE_TEMPLATE(orderInfo.getOrderNo(), orderFee.getName(), price.getPrice(), price.getRemark()))
            .build());

        return true;
    }

    /**
     * 上传订单打款凭证
     *
     * @param payment
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean insertPayment(AdminUploadBillBo payment) {
        Long id = payment.getMasterId();
        OrderInfo orderInfo = orderInfoMapper.selectById(id);
        if (orderInfo == null) {
            throw new ServiceException("订单不存在");
        }
        // 只有待回单状态下的运单可以上传回单
        if (!OrderStatus.WAITING_FOR_PAYMENT.getCode().equals(orderInfo.getOrderStatus())) {
            throw new ServiceException("只有在待打款状态下的订单可以上传打款凭证");
        }

        boolean delete = paymentVoucherMapper.deleteByOrderId(payment.getMasterId());
        OrderPaymentVoucher orderPaymentVoucher = new OrderPaymentVoucher();
        orderPaymentVoucher.setOrderId(payment.getMasterId());
        orderPaymentVoucher.setUrl(payment.getUrl());
        orderPaymentVoucher.setRemark(payment.getRemark());
        int insert = paymentVoucherMapper.insert(orderPaymentVoucher);

        if (insert > 0) {
            // 修改订单状态
            int update = orderInfoMapper.updateStatus(id, OrderStatus.COMPLETED.getCode());
            if (update > 0) {
                //     更新可开票金额
                orderInfoMapper.updateInvoiceAmount(id, orderInfo.getOrderTotalPrices());
            }
        }
        return insert > 0;
    }

    /**
     * 获取订单列表
     *
     * @param orderQueryBo 订单列表查询bo
     * @param pageQuery    分页查询
     * @return
     */
    @Override
    public TableDataInfo<OrderInfoVo> listOrder(AdminOrderQueryBo orderQueryBo, PageQuery pageQuery) {
        QueryWrapper queryWrapper = this.generateQueryWrapper(orderQueryBo);

        IPage<OrderInfoVo> result = orderInfoMapper.selectVoPage(pageQuery.build(), queryWrapper);

        return TableDataInfo.build(result);
    }

    /**
     * 获取订单费用配置项列表
     *
     * @return
     */
    // @Cacheable(cacheNames = CacheNames.ORDER_FEE_CONFIG)
    @Override
    public List<OrderFeeConfigVo> selectFeeConfigList() {
        QueryWrapper<OrderFeeConfig> qw = new QueryWrapper<>();
        qw.lambda().eq(OrderFeeConfig::getStatus, Constants.SUCCESS);

        return feeConfigMapper.selectVoList(qw);
    }

    /**
     * 获取订单改价历史列表
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    public AdminOrderRevaluationVo listOrderPrice(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo == null) {
            throw new ServiceException("订单不存在");
        }

        List<OrderRevaluationHistoryVo> revaluationHistoryVoList = revaluationHistoryMapper.selectVoList(new QueryWrapper<OrderRevaluationHistory>()
            .lambda()
            .eq(OrderRevaluationHistory::getOrderId, orderId)
            .orderByDesc(OrderRevaluationHistory::getCreateTime));

        AdminOrderRevaluationVo revaluationVo = new AdminOrderRevaluationVo();
        revaluationVo.setOrderId(orderId);
        revaluationVo.setOrderStatus(orderInfo.getOrderStatus());
        revaluationVo.setOrderNo(orderInfo.getOrderNo());

        revaluationVo.setHistoryList(revaluationHistoryVoList);


        return revaluationVo;
    }

    /**
     * 导出订单列表
     *
     * @param orderQueryBo
     * @return
     */
    @Override
    public List<AdminOrderExportVo> listExportOrder(AdminOrderQueryBo orderQueryBo) {
        List<AdminOrderExportVo> list = orderInfoMapper.selectExportVoList(orderQueryBo);
        for (AdminOrderExportVo item : list) {
            item.setSendProvinceLabel(areaService.selectAreaNameById(item.getSendProvince()));
            item.setSendCityLabel(areaService.selectAreaNameById(item.getSendCity()));
            item.setSendDistrictLabel(areaService.selectAreaNameById(item.getSendDistrict()));

            item.setReceiverProvinceLabel(areaService.selectAreaNameById(item.getReceiverProvince()));
            item.setReceiverCityLabel(areaService.selectAreaNameById(item.getReceiverCity()));
            item.setReceiverDistrictLabel(areaService.selectAreaNameById(item.getReceiverDistrict()));
        }
        return list;
    }

    private QueryWrapper generateQueryWrapper(AdminOrderQueryBo orderQueryBo) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
            .in(orderQueryBo.getOrderStatusList() != null && !orderQueryBo.getOrderStatusList().isEmpty(),
                OrderInfo::getOrderStatus, orderQueryBo.getOrderStatusList())
            .like(StrUtil.isNotEmpty(orderQueryBo.getOrderNo()), OrderInfo::getOrderNo, orderQueryBo.getOrderNo())
            .like(StrUtil.isNotEmpty(orderQueryBo.getCompanyName()), OrderInfo::getSendCompanyName, orderQueryBo.getCompanyName())
            .eq(StrUtil.isNotEmpty(orderQueryBo.getCompanyPhone()), OrderInfo::getSendPhone, orderQueryBo.getCompanyPhone())
            .eq(StrUtil.isNotEmpty(orderQueryBo.getCarUseType()), OrderInfo::getCarUseType, orderQueryBo.getCarUseType())
            .ge(ObjectUtil.isNotNull(orderQueryBo.getOrderStartTime()), OrderInfo::getCreateTime, orderQueryBo.getOrderStartTime())
            .le(ObjectUtil.isNotNull(orderQueryBo.getOrderEndTime()), OrderInfo::getCreateTime, orderQueryBo.getOrderEndTime())
            .orderByDesc(OrderInfo::getCreateTime);
        return queryWrapper;
    }
}
